<script setup lang="ts">
import { ref, reactive, markRaw, nextTick, type Raw, type ComponentPublicInstance } from 'vue'
import type { NotifyOptions } from './types'
import { nextKey } from '../util'
import { messageClassOf, messageIconOf } from '../message'
import Notify from './Notify.vue'
import type { MessageType } from '../message/types'
import { slideInRight, slideOutRight } from '../effect'

interface NotifyItem {
  key: string
  icon?: string
  title?: string
  content: string
  closeable: boolean
  buttons?: {
    name: string
    type?: 'primary' | 'info' | 'success' | 'warning' | 'danger'
    handle: () => void
  }[]
}

function getIcon(opts: NotifyOptions, type?: MessageType): string | undefined {
  if (!opts.icon && !type) {
    return undefined
  }
  if (!type) {
    return opts.icon
  }
  const icon = opts.icon || messageIconOf(type)
  const clz = messageClassOf(type)
  return `${icon} ${clz}`
}

function elementOf(key: string): HTMLElement | null {
  const idx = items.findIndex((e) => e.key === key)
  if (idx === -1) {
    return null
  }
  const lst = notify.value
  if (!lst) {
    return null
  }
  const i = lst[idx]
  return i.$el
}

function create(opts: NotifyOptions, type?: MessageType): string {
  const key = nextKey()
  const item: NotifyItem = {
    key,
    icon: getIcon(opts, type),
    title: opts.title,
    content: opts.content,
    buttons: opts.buttons,
    closeable: opts.closeable != null ? opts.closeable : true
  }
  items.push(markRaw(item))
  nextTick(() => {
    const e = elementOf(key)
    if (e) {
      slideInRight(e, 150)
    }
  })
  let d = opts.duration != null ? opts.duration : 2000
  if (d > 0) {
    d = Math.max(1000.0, d)
    setTimeout(() => destroy(key), d + 150)
  }
  return key
}

async function destroy(key: string) {
  const e = elementOf(key)
  if (!e) {
    return
  }
  await slideOutRight(e, 200)
  const i = items.findIndex((e) => e.key === key)
  if (i != -1) {
    items.splice(i, 1)
  }
}

defineExpose({ create, destroy })

const items = reactive<Raw<NotifyItem>[]>([])
const notify = ref<ComponentPublicInstance[] | null>(null)
</script>
<template>
  <div id="notify-container">
    <Notify
      ref="notify"
      v-for="item in items"
      :key="item.key"
      :icon="item.icon"
      :title="item.title"
      :content="item.content"
      :buttons="item.buttons"
      :closeable="item.closeable"
      @hide="destroy(item.key)"
    />
  </div>
</template>
